home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / python2.6 / smtpd.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2009-11-11  |  16KB  |  545 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. """An RFC 2821 smtp proxy.
  5.  
  6. Usage: %(program)s [options] [localhost:localport [remotehost:remoteport]]
  7.  
  8. Options:
  9.  
  10.     --nosetuid
  11.     -n
  12.         This program generally tries to setuid `nobody', unless this flag is
  13.         set.  The setuid call will fail if this program is not run as root (in
  14.         which case, use this flag).
  15.  
  16.     --version
  17.     -V
  18.         Print the version number and exit.
  19.  
  20.     --class classname
  21.     -c classname
  22.         Use `classname' as the concrete SMTP proxy class.  Uses `PureProxy' by
  23.         default.
  24.  
  25.     --debug
  26.     -d
  27.         Turn on debugging prints.
  28.  
  29.     --help
  30.     -h
  31.         Print this message and exit.
  32.  
  33. Version: %(__version__)s
  34.  
  35. If localhost is not given then `localhost' is used, and if localport is not
  36. given then 8025 is used.  If remotehost is not given then `localhost' is used,
  37. and if remoteport is not given, then 25 is used.
  38. """
  39. import sys
  40. import os
  41. import errno
  42. import getopt
  43. import time
  44. import socket
  45. import asyncore
  46. import asynchat
  47. __all__ = [
  48.     'SMTPServer',
  49.     'DebuggingServer',
  50.     'PureProxy',
  51.     'MailmanProxy']
  52. program = sys.argv[0]
  53. __version__ = 'Python SMTP proxy version 0.2'
  54.  
  55. class Devnull:
  56.     
  57.     def write(self, msg):
  58.         pass
  59.  
  60.     
  61.     def flush(self):
  62.         pass
  63.  
  64.  
  65. DEBUGSTREAM = Devnull()
  66. NEWLINE = '\n'
  67. EMPTYSTRING = ''
  68. COMMASPACE = ', '
  69.  
  70. def usage(code, msg = ''):
  71.     print >>sys.stderr, __doc__ % globals()
  72.     if msg:
  73.         print >>sys.stderr, msg
  74.     
  75.     sys.exit(code)
  76.  
  77.  
  78. class SMTPChannel(asynchat.async_chat):
  79.     COMMAND = 0
  80.     DATA = 1
  81.     
  82.     def __init__(self, server, conn, addr):
  83.         asynchat.async_chat.__init__(self, conn)
  84.         self._SMTPChannel__server = server
  85.         self._SMTPChannel__conn = conn
  86.         self._SMTPChannel__addr = addr
  87.         self._SMTPChannel__line = []
  88.         self._SMTPChannel__state = self.COMMAND
  89.         self._SMTPChannel__greeting = 0
  90.         self._SMTPChannel__mailfrom = None
  91.         self._SMTPChannel__rcpttos = []
  92.         self._SMTPChannel__data = ''
  93.         self._SMTPChannel__fqdn = socket.getfqdn()
  94.         self._SMTPChannel__peer = conn.getpeername()
  95.         print >>DEBUGSTREAM, 'Peer:', repr(self._SMTPChannel__peer)
  96.         self.push('220 %s %s' % (self._SMTPChannel__fqdn, __version__))
  97.         self.set_terminator('\r\n')
  98.  
  99.     
  100.     def push(self, msg):
  101.         asynchat.async_chat.push(self, msg + '\r\n')
  102.  
  103.     
  104.     def collect_incoming_data(self, data):
  105.         self._SMTPChannel__line.append(data)
  106.  
  107.     
  108.     def found_terminator(self):
  109.         line = EMPTYSTRING.join(self._SMTPChannel__line)
  110.         print >>DEBUGSTREAM, 'Data:', repr(line)
  111.         self._SMTPChannel__line = []
  112.         if self._SMTPChannel__state == self.COMMAND:
  113.             if not line:
  114.                 self.push('500 Error: bad syntax')
  115.                 return None
  116.             method = None
  117.             i = line.find(' ')
  118.             if i < 0:
  119.                 command = line.upper()
  120.                 arg = None
  121.             else:
  122.                 command = line[:i].upper()
  123.                 arg = line[i + 1:].strip()
  124.             method = getattr(self, 'smtp_' + command, None)
  125.             if not method:
  126.                 self.push('502 Error: command "%s" not implemented' % command)
  127.                 return None
  128.             method(arg)
  129.             return None
  130.         if self._SMTPChannel__state != self.DATA:
  131.             self.push('451 Internal confusion')
  132.             return None
  133.         data = []
  134.         for text in line.split('\r\n'):
  135.             if text and text[0] == '.':
  136.                 data.append(text[1:])
  137.                 continue
  138.             self._SMTPChannel__state != self.DATA
  139.             data.append(text)
  140.         
  141.         self._SMTPChannel__data = NEWLINE.join(data)
  142.         status = self._SMTPChannel__server.process_message(self._SMTPChannel__peer, self._SMTPChannel__mailfrom, self._SMTPChannel__rcpttos, self._SMTPChannel__data)
  143.         self._SMTPChannel__rcpttos = []
  144.         self._SMTPChannel__mailfrom = None
  145.         self._SMTPChannel__state = self.COMMAND
  146.         self.set_terminator('\r\n')
  147.         if not status:
  148.             self.push('250 Ok')
  149.         else:
  150.             self.push(status)
  151.  
  152.     
  153.     def smtp_HELO(self, arg):
  154.         if not arg:
  155.             self.push('501 Syntax: HELO hostname')
  156.             return None
  157.         if self._SMTPChannel__greeting:
  158.             self.push('503 Duplicate HELO/EHLO')
  159.         else:
  160.             self._SMTPChannel__greeting = arg
  161.             self.push('250 %s' % self._SMTPChannel__fqdn)
  162.  
  163.     
  164.     def smtp_NOOP(self, arg):
  165.         if arg:
  166.             self.push('501 Syntax: NOOP')
  167.         else:
  168.             self.push('250 Ok')
  169.  
  170.     
  171.     def smtp_QUIT(self, arg):
  172.         self.push('221 Bye')
  173.         self.close_when_done()
  174.  
  175.     
  176.     def __getaddr(self, keyword, arg):
  177.         address = None
  178.         keylen = len(keyword)
  179.         if arg[:keylen].upper() == keyword:
  180.             address = arg[keylen:].strip()
  181.             if not address:
  182.                 pass
  183.             elif address[0] == '<' and address[-1] == '>' and address != '<>':
  184.                 address = address[1:-1]
  185.             
  186.         
  187.         return address
  188.  
  189.     
  190.     def smtp_MAIL(self, arg):
  191.         print >>DEBUGSTREAM, '===> MAIL', arg
  192.         address = None if arg else None
  193.         if not address:
  194.             self.push('501 Syntax: MAIL FROM:<address>')
  195.             return None
  196.         if self._SMTPChannel__mailfrom:
  197.             self.push('503 Error: nested MAIL command')
  198.             return None
  199.         self._SMTPChannel__mailfrom = address
  200.         print >>DEBUGSTREAM, 'sender:', self._SMTPChannel__mailfrom
  201.         self.push('250 Ok')
  202.  
  203.     
  204.     def smtp_RCPT(self, arg):
  205.         print >>DEBUGSTREAM, '===> RCPT', arg
  206.         if not self._SMTPChannel__mailfrom:
  207.             self.push('503 Error: need MAIL command')
  208.             return None
  209.         address = self._SMTPChannel__mailfrom if arg else None
  210.         if not address:
  211.             self.push('501 Syntax: RCPT TO: <address>')
  212.             return None
  213.         self._SMTPChannel__rcpttos.append(address)
  214.         print >>DEBUGSTREAM, 'recips:', self._SMTPChannel__rcpttos
  215.         self.push('250 Ok')
  216.  
  217.     
  218.     def smtp_RSET(self, arg):
  219.         if arg:
  220.             self.push('501 Syntax: RSET')
  221.             return None
  222.         self._SMTPChannel__mailfrom = None
  223.         self._SMTPChannel__rcpttos = []
  224.         self._SMTPChannel__data = ''
  225.         self._SMTPChannel__state = self.COMMAND
  226.         self.push('250 Ok')
  227.  
  228.     
  229.     def smtp_DATA(self, arg):
  230.         if not self._SMTPChannel__rcpttos:
  231.             self.push('503 Error: need RCPT command')
  232.             return None
  233.         if arg:
  234.             self.push('501 Syntax: DATA')
  235.             return None
  236.         self._SMTPChannel__state = self.DATA
  237.         self.set_terminator('\r\n.\r\n')
  238.         self.push('354 End data with <CR><LF>.<CR><LF>')
  239.  
  240.  
  241.  
  242. class SMTPServer(asyncore.dispatcher):
  243.     
  244.     def __init__(self, localaddr, remoteaddr):
  245.         self._localaddr = localaddr
  246.         self._remoteaddr = remoteaddr
  247.         asyncore.dispatcher.__init__(self)
  248.         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
  249.         self.set_reuse_addr()
  250.         self.bind(localaddr)
  251.         self.listen(5)
  252.         print >>DEBUGSTREAM, '%s started at %s\n\tLocal addr: %s\n\tRemote addr:%s' % (self.__class__.__name__, time.ctime(time.time()), localaddr, remoteaddr)
  253.  
  254.     
  255.     def handle_accept(self):
  256.         (conn, addr) = self.accept()
  257.         print >>DEBUGSTREAM, 'Incoming connection from %s' % repr(addr)
  258.         channel = SMTPChannel(self, conn, addr)
  259.  
  260.     
  261.     def process_message(self, peer, mailfrom, rcpttos, data):
  262.         """Override this abstract method to handle messages from the client.
  263.  
  264.         peer is a tuple containing (ipaddr, port) of the client that made the
  265.         socket connection to our smtp port.
  266.  
  267.         mailfrom is the raw address the client claims the message is coming
  268.         from.
  269.  
  270.         rcpttos is a list of raw addresses the client wishes to deliver the
  271.         message to.
  272.  
  273.         data is a string containing the entire full text of the message,
  274.         headers (if supplied) and all.  It has been `de-transparencied'
  275.         according to RFC 821, Section 4.5.2.  In other words, a line
  276.         containing a `.' followed by other text has had the leading dot
  277.         removed.
  278.  
  279.         This function should return None, for a normal `250 Ok' response;
  280.         otherwise it returns the desired response string in RFC 821 format.
  281.  
  282.         """
  283.         raise NotImplementedError
  284.  
  285.  
  286.  
  287. class DebuggingServer(SMTPServer):
  288.     
  289.     def process_message(self, peer, mailfrom, rcpttos, data):
  290.         inheaders = 1
  291.         lines = data.split('\n')
  292.         print '---------- MESSAGE FOLLOWS ----------'
  293.         for line in lines:
  294.             if inheaders and not line:
  295.                 print 'X-Peer:', peer[0]
  296.                 inheaders = 0
  297.             
  298.             print line
  299.         
  300.         print '------------ END MESSAGE ------------'
  301.  
  302.  
  303.  
  304. class PureProxy(SMTPServer):
  305.     
  306.     def process_message(self, peer, mailfrom, rcpttos, data):
  307.         lines = data.split('\n')
  308.         i = 0
  309.         for line in lines:
  310.             if not line:
  311.                 break
  312.             
  313.             i += 1
  314.         
  315.         lines.insert(i, 'X-Peer: %s' % peer[0])
  316.         data = NEWLINE.join(lines)
  317.         refused = self._deliver(mailfrom, rcpttos, data)
  318.         print >>DEBUGSTREAM, 'we got some refusals:', refused
  319.  
  320.     
  321.     def _deliver(self, mailfrom, rcpttos, data):
  322.         import smtplib as smtplib
  323.         refused = { }
  324.         
  325.         try:
  326.             s = smtplib.SMTP()
  327.             s.connect(self._remoteaddr[0], self._remoteaddr[1])
  328.             
  329.             try:
  330.                 refused = s.sendmail(mailfrom, rcpttos, data)
  331.             finally:
  332.                 s.quit()
  333.  
  334.         except smtplib.SMTPRecipientsRefused:
  335.             e = None
  336.             print >>DEBUGSTREAM, 'got SMTPRecipientsRefused'
  337.             refused = e.recipients
  338.         except (socket.error, smtplib.SMTPException):
  339.             e = None
  340.             print >>DEBUGSTREAM, 'got', e.__class__
  341.             errcode = getattr(e, 'smtp_code', -1)
  342.             errmsg = getattr(e, 'smtp_error', 'ignore')
  343.             for r in rcpttos:
  344.                 refused[r] = (errcode, errmsg)
  345.             
  346.  
  347.         return refused
  348.  
  349.  
  350.  
  351. class MailmanProxy(PureProxy):
  352.     
  353.     def process_message(self, peer, mailfrom, rcpttos, data):
  354.         StringIO = StringIO
  355.         import cStringIO
  356.         Utils = Utils
  357.         import Mailman
  358.         Message = Message
  359.         import Mailman
  360.         MailList = MailList
  361.         import Mailman
  362.         listnames = []
  363.         for rcpt in rcpttos:
  364.             local = rcpt.lower().split('@')[0]
  365.             parts = local.split('-')
  366.             if len(parts) > 2:
  367.                 continue
  368.             
  369.             listname = parts[0]
  370.             if len(parts) == 2:
  371.                 command = parts[1]
  372.             else:
  373.                 command = ''
  374.             if not Utils.list_exists(listname) or command not in ('', 'admin', 'owner', 'request', 'join', 'leave'):
  375.                 continue
  376.             
  377.             listnames.append((rcpt, listname, command))
  378.         
  379.         for rcpt, listname, command in listnames:
  380.             rcpttos.remove(rcpt)
  381.         
  382.         print >>DEBUGSTREAM, 'forwarding recips:', ' '.join(rcpttos)
  383.         if rcpttos:
  384.             refused = self._deliver(mailfrom, rcpttos, data)
  385.             print >>DEBUGSTREAM, 'we got refusals:', refused
  386.         
  387.         mlists = { }
  388.         s = StringIO(data)
  389.         msg = Message.Message(s)
  390.         if not msg.getheader('from'):
  391.             msg['From'] = mailfrom
  392.         
  393.         if not msg.getheader('date'):
  394.             msg['Date'] = time.ctime(time.time())
  395.         
  396.         for rcpt, listname, command in listnames:
  397.             print >>DEBUGSTREAM, 'sending message to', rcpt
  398.             mlist = mlists.get(listname)
  399.             if not mlist:
  400.                 mlist = MailList.MailList(listname, lock = 0)
  401.                 mlists[listname] = mlist
  402.             
  403.             if command == '':
  404.                 msg.Enqueue(mlist, tolist = 1)
  405.                 continue
  406.             if command == 'admin':
  407.                 msg.Enqueue(mlist, toadmin = 1)
  408.                 continue
  409.             if command == 'owner':
  410.                 msg.Enqueue(mlist, toowner = 1)
  411.                 continue
  412.             if command == 'request':
  413.                 msg.Enqueue(mlist, torequest = 1)
  414.                 continue
  415.             if command in ('join', 'leave'):
  416.                 if command == 'join':
  417.                     msg['Subject'] = 'subscribe'
  418.                 else:
  419.                     msg['Subject'] = 'unsubscribe'
  420.                 msg.Enqueue(mlist, torequest = 1)
  421.                 continue
  422.         
  423.  
  424.  
  425.  
  426. class Options:
  427.     setuid = 1
  428.     classname = 'PureProxy'
  429.  
  430.  
  431. def parseargs():
  432.     global DEBUGSTREAM
  433.     
  434.     try:
  435.         (opts, args) = getopt.getopt(sys.argv[1:], 'nVhc:d', [
  436.             'class=',
  437.             'nosetuid',
  438.             'version',
  439.             'help',
  440.             'debug'])
  441.     except getopt.error:
  442.         e = None
  443.         usage(1, e)
  444.  
  445.     options = Options()
  446.     for opt, arg in opts:
  447.         if opt in ('-h', '--help'):
  448.             usage(0)
  449.             continue
  450.         if opt in ('-V', '--version'):
  451.             print >>sys.stderr, __version__
  452.             sys.exit(0)
  453.             continue
  454.         if opt in ('-n', '--nosetuid'):
  455.             options.setuid = 0
  456.             continue
  457.         if opt in ('-c', '--class'):
  458.             options.classname = arg
  459.             continue
  460.         if opt in ('-d', '--debug'):
  461.             DEBUGSTREAM = sys.stderr
  462.             continue
  463.     
  464.     if len(args) < 1:
  465.         localspec = 'localhost:8025'
  466.         remotespec = 'localhost:25'
  467.     elif len(args) < 2:
  468.         localspec = args[0]
  469.         remotespec = 'localhost:25'
  470.     elif len(args) < 3:
  471.         localspec = args[0]
  472.         remotespec = args[1]
  473.     else:
  474.         usage(1, 'Invalid arguments: %s' % COMMASPACE.join(args))
  475.     i = localspec.find(':')
  476.     if i < 0:
  477.         usage(1, 'Bad local spec: %s' % localspec)
  478.     
  479.     options.localhost = localspec[:i]
  480.     
  481.     try:
  482.         options.localport = int(localspec[i + 1:])
  483.     except ValueError:
  484.         usage(1, 'Bad local port: %s' % localspec)
  485.  
  486.     i = remotespec.find(':')
  487.     if i < 0:
  488.         usage(1, 'Bad remote spec: %s' % remotespec)
  489.     
  490.     options.remotehost = remotespec[:i]
  491.     
  492.     try:
  493.         options.remoteport = int(remotespec[i + 1:])
  494.     except ValueError:
  495.         usage(1, 'Bad remote port: %s' % remotespec)
  496.  
  497.     return options
  498.  
  499. if __name__ == '__main__':
  500.     options = parseargs()
  501.     if options.setuid:
  502.         
  503.         try:
  504.             import pwd
  505.         except ImportError:
  506.             print >>sys.stderr, 'Cannot import module "pwd"; try running with -n option.'
  507.             sys.exit(1)
  508.  
  509.         nobody = pwd.getpwnam('nobody')[2]
  510.         
  511.         try:
  512.             os.setuid(nobody)
  513.         except OSError:
  514.             e = None
  515.             if e.errno != errno.EPERM:
  516.                 raise 
  517.             e.errno != errno.EPERM
  518.             print >>sys.stderr, 'Cannot setuid "nobody"; try running with -n option.'
  519.             sys.exit(1)
  520.         except:
  521.             None<EXCEPTION MATCH>OSError
  522.         
  523.  
  524.     None<EXCEPTION MATCH>OSError
  525.     classname = options.classname
  526.     if '.' in classname:
  527.         lastdot = classname.rfind('.')
  528.         mod = __import__(classname[:lastdot], globals(), locals(), [
  529.             ''])
  530.         classname = classname[lastdot + 1:]
  531.     else:
  532.         import __main__ as mod
  533.     class_ = getattr(mod, classname)
  534.     proxy = class_((options.localhost, options.localport), (options.remotehost, options.remoteport))
  535.     
  536.     try:
  537.         asyncore.loop()
  538.     except KeyboardInterrupt:
  539.         pass
  540.     except:
  541.         None<EXCEPTION MATCH>KeyboardInterrupt
  542.     
  543.  
  544. None<EXCEPTION MATCH>KeyboardInterrupt
  545.